package org.scboy.dbms.service.imp;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;

import org.scboy.coobi.sql.factory.EntityFactory;
import org.scboy.dbms.dao.BaseAppConfigDao;
import org.scboy.dbms.dao.BaseAppFileDao;
import org.scboy.dbms.dao.BaseAppServerDao;
import org.scboy.dbms.dao.BaseServersDao;
import org.scboy.dbms.enums.DocType;
import org.scboy.dbms.service.BaseAppServerService;
import org.scboy.dbms.sftp.SftpClient;
import org.scboy.dbms.sftp.SshClient;
import org.scboy.dbms.utils.ConfigUtil;
import org.scboy.utils.entitys.coobi.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

@Service
@Configuration
public class BaseAppServerServiceImp implements BaseAppServerService {

	Log log=LogFactory.get();
	
	@Autowired
	EntityFactory factory;
	
	@Override
	public List<Model> list(Model params) {
		BaseAppServerDao dao =factory.getDao(BaseAppServerDao.class);
		return dao.select(params);
	}

	@Override
	public boolean addApp(Model params) {
		
		BaseAppFileDao dao =factory.getDao(BaseAppFileDao.class);
		
		BaseAppServerDao serverDao=factory.getDao(BaseAppServerDao.class);
		
		//服务器地址
		String ip=params.getString("ip");
		
		//微服务名称集合
		String appName=params.getString("appName");
		
		//端口集合
		int port=params.getInt("port");
		
		//检查其他微服务是否占用了端口
		if(serverDao.count(Model.create().add("ip", ip).add("port", port).NE("appName", appName))>0) {
			return false;
		}
		
		//获取二进制文件
		byte[] appBinary=dao.get(Model.create().add("appName", appName)).getBytes("appBinary");
		
		//上传
		return uploadApp(ip, appName, port, appBinary);
	}
	
	/**
	 * 上传微服务到服务器
	 */
	public boolean uploadApp(String ip,String appName,int mPort,byte[] appBinary) {
		
		BaseServersDao serverDao=factory.getDao(BaseServersDao.class);
		
		BaseAppConfigDao configDao=factory.getDao(BaseAppConfigDao.class);
		
		BaseAppServerDao appServerDao=factory.getDao(BaseAppServerDao.class);
		
		Model config = configDao.get(Model.create().add("appName", appName).add("activity", 1).addRc("configValue").addRc("docType"));

		String docType= config.getString("docType");
		//获取服务器信息
		Model server=serverDao.get(Model.create().add("ip", ip));
		//管理端口
		Integer serverPort= server.getInt("port");
		//管理账号
		String user= server.getString("adminAccount");
		//管理密码
		String password= server.getString("adminPassword");
		//服务器的部署路径
		String serverPath= server.getString("serverPath");

		//构建Path
		String path=serverPath+"/"+appName+"-"+mPort;
		
		if(serverPort==null) {
			serverPort=22;
		}
		
		SftpClient client=null;
		try {
			client=new SftpClient(ip, serverPort, user, password);
		} catch (Exception e) {
			log.error(e);
			return false;
		}
		
		
		try {
			//上传安装文件包
			//检查部署的文件路径是否存在
			boolean dirExist= client.isDirExist(path);
			if(!dirExist) {
				client.mkdirs(path);
			}
			//判断Jar文件是否存在
			boolean jarExist=client.fileExist(path, appName+"-exe.jar");
			if(jarExist) {
				String oldJarFile=path+"/"+appName+"-exe.jar";
				String backJarFile=path+"/"+appName+"-exe-"+DateUtil.format(new Date(), "yyyyMMddHHmmss")+".bak";
				client.rename(oldJarFile, backJarFile);
			}
			InputStream jarInput=IoUtil.toStream(appBinary);
			client.upload(path, appName+"-exe.jar", jarInput);
			
			/**
			 * 上传配置文件
			 */
			
			//检查配置文件路径是否存在
			String configPath=path+"/"+"config";
			boolean dirConfigExist= client.isDirExist(configPath);
			if(!dirConfigExist) {
				client.mkdirs(configPath);
			}
			
			//判断配置文件是否存在
			boolean configExist=client.fileExist(configPath, "application.properties");
			if(configExist) {
				String oldConfigFile=configPath+"/"+"application.properties";
				String backConfigFile=configPath+"/"+"application-"+DateUtil.format(new Date(), "yyyyMMddHHmmss")+".bak";
				client.rename(oldConfigFile, backConfigFile);
			}
			
			String configValue=config.getString("configValue");

			//改变端口
			ConfigUtil configUtil =null;
			if("yml".equals(docType)) {
				configUtil = ConfigUtil.load(configValue, DocType.YAML);
			}else {
				configUtil = ConfigUtil.load(configValue, DocType.PROPERTIES);
			}
			configUtil.setValue("server.port", mPort+"");
			configValue=configUtil.text();
			
			InputStream input=IoUtil.toStream(configValue, Charset.defaultCharset());
			client.upload(configPath, "application.properties", input);
			
			//检查是否部署情况是否存在
			long count=appServerDao.count(Model.create().add("appName", appName).add("ip", ip).add("port", mPort));
			if(count==0) {
				appServerDao.insert(
						Model.create().add("id", UUID.randomUUID().toString())
						.add("appName", appName)
						.add("ip", ip)
						.add("port", mPort)
						.add("deploymentPath", path)
						.add("status", 0)
				);
			}
			
			client.close();
			return true;
		} catch (IOException e) {
			client.close();
			log.error(e);
			return false;
		}
	}
	
	
	@Override
	public boolean update(Model params) {
		BaseAppServerDao dao =factory.getDao(BaseAppServerDao.class);
		int count= dao.update(params);
		if(count>0) {
			return true;
		}else {
			return false;
		}
	}

	@Override
	public List<Model> listAll() {
		BaseAppServerDao dao =factory.getDao(BaseAppServerDao.class);
		return dao.queryList(Model.create());
	}

	@Override
	public void stop(String ip, String appName, String id) {
		BaseAppServerDao dao =factory.getDao(BaseAppServerDao.class);
		Model params=Model.create();
		if(StrUtil.isNotEmpty(ip)) {
			params.add("ip", ip);
		}
		if(StrUtil.isNotEmpty(appName)) {
			params.add("appName", appName);
		}
		if(StrUtil.isNotEmpty(id)) {
			params.add("id", id);
		}
		params.add("status", 2);
		params.add("orderByDesc", true);
		List<Model> appServers=dao.queryList(params);
		for (Model appServer : appServers) {
			try {
				String url="http://"+appServer.getString("ip")+":"+appServer.getString("port")+"/actuator/shutdown";
				HttpUtil.post(url, "{}");
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}

	@Override
	public void restart(String ip, String appName, String id) {
		BaseAppServerDao dao =factory.getDao(BaseAppServerDao.class);
		Model params=Model.create();
		if(StrUtil.isNotEmpty(ip)) {
			params.add("ip", ip);
		}
		if(StrUtil.isNotEmpty(appName)) {
			params.add("appName", appName);
		}
		if(StrUtil.isNotEmpty(id)) {
			params.add("id", id);
		}
		params.add("status", 2);
		params.add("orderByDesc", true);
		List<Model> appServers=dao.queryList(params);
		for (Model appServer : appServers) {
			try {
				//关闭服务
				stop("", "", appServer.getString("id"));
				boolean start=false;
				while (!start) {
					int state=dao.get(Model.create().add("id", appServer.get("id")).addRc("status")).getInt("status");
					if(state==0) {
						start=true;
					}
					Thread.sleep(1000);
				}
				//启动服务
				start("", "", appServer.getString("id"));
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}

	@Override
	public void start(String ip, String appName, String id) {
		BaseAppServerDao dao =factory.getDao(BaseAppServerDao.class);
		BaseServersDao serverDao=factory.getDao(BaseServersDao.class);
		
		Model params=Model.create();
		if(StrUtil.isNotEmpty(ip)) {
			params.add("ip", ip);
		}
		if(StrUtil.isNotEmpty(appName)) {
			params.add("appName", appName);
		}
		if(StrUtil.isNotEmpty(id)) {
			params.add("id", id);
		}
		params.add("status", 0);
		List<Model> appServers=dao.queryList(params);
		for (Model appServer : appServers) {
			Model server=serverDao.get(Model.create().add("ip", appServer.getString("ip")));
			try {
				SshClient client=new SshClient(ip, server.getInt("port"), server.getString("adminAccount"), server.getString("adminPassword"));
				String cmd="nohup java -jar "+appServer.getString("deploymentPath")+"/"+appServer.getString("appName")+"-exe.jar  2>&1 &";
				client.exeCommand(cmd);
				client.close();
			} catch (Exception e) {
				
			}
		}
	}

}
